home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / SpriteWorld files / Utils / Circular Scrolling.c < prev    next >
Encoding:
Text File  |  1999-01-12  |  48.1 KB  |  1,631 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. //    Circular Scrolling.c
  3. //
  4. //    By:    Vern Jensen
  5. //    
  6. //    Created: 7/20/96
  7. //
  8. //    Description:    Routines that enable you to wrap around while scrolling
  9. //
  10. //    Implementation note: Unlike the standard scrolling engine, Sprites and the visScrollRect
  11. //    in this engine will only hang off the right and bottom edges of the offscreen area when
  12. //    wrapping, not the top and left. This was done to simplify the code in various sections. 
  13. //    It could be done in the standard scrolling engine as well if we want.
  14. //
  15. //    As for how the engine works, it first clips the visScrollRect with the circular world's
  16. //    bounds, wraps each part, and calls a function to draw the sprites in each part. This
  17. //    function clips each sprite with the circular world's bounds, and draws each part,
  18. //    clipping it to the current piece of the visScrollRect it's being drawn in. It may sound
  19. //    complex, but it's the only way to do it without running into other problems.
  20. ///--------------------------------------------------------------------------------------
  21.  
  22.  
  23.  
  24. #ifndef __QUICKDRAW__
  25. #include <QuickDraw.h>
  26. #endif
  27.  
  28. #ifndef __MEMORY__
  29. #include <Memory.h>
  30. #endif
  31.  
  32. #ifndef __GESTALT__
  33. #include <Gestalt.h>
  34. #endif
  35.  
  36. #ifndef __SPRITEWORLD__
  37. #include "SpriteWorld.h"
  38. #endif
  39.  
  40. #ifndef __SPRITEWORLDUTILS__
  41. #include "SpriteWorldUtils.h"
  42. #endif
  43.  
  44. #ifndef __BLITPIXIE__
  45. #include "BlitPixie.h"
  46. #endif
  47.  
  48. #ifndef __SCROLLING__
  49. #include "Scrolling.h"
  50. #endif
  51.  
  52. #ifndef __TILING__
  53. #include "Tiling.h"
  54. #endif
  55.  
  56. #ifndef __CIRCULARSCROLLING__
  57. #include "Circular Scrolling.h"
  58. #endif
  59.  
  60.  
  61. extern    SpritePtr        gCurrentSpriteBeingDrawn;
  62.  
  63.  
  64. ///--------------------------------------------------------------------------------------
  65. //    SWUpdateCircularSpriteWorld
  66. ///--------------------------------------------------------------------------------------
  67.  
  68. SW_FUNC void SWUpdateCircularSpriteWorld(
  69.     SpriteWorldPtr spriteWorldP)
  70. {
  71.     GWorldPtr    saveGWorld;
  72.     GDHandle    saveGDH;
  73.     
  74.     SW_ASSERT(spriteWorldP != NULL);
  75.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  76.     SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
  77.     
  78.     GetGWorld( &saveGWorld, &saveGDH );
  79.  
  80.         // Copy the background into the work area
  81.     SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  82.     (*spriteWorldP->offscreenDrawProc)(spriteWorldP->backFrameP,
  83.                         spriteWorldP->workFrameP,
  84.                         &spriteWorldP->backFrameP->frameRect,
  85.                         &spriteWorldP->workFrameP->frameRect);
  86.     
  87.     
  88.     spriteWorldP->frameHasOccurred = true;
  89.     SWAnimateCircularSpriteWorld(spriteWorldP);
  90.     
  91.     SetGWorld( saveGWorld, saveGDH );
  92. }
  93.  
  94.  
  95. ///--------------------------------------------------------------------------------------
  96. //    SWProcessCircularSpriteWorld
  97. ///--------------------------------------------------------------------------------------
  98.  
  99. SW_FUNC void SWProcessCircularSpriteWorld(
  100.     SpriteWorldPtr spriteWorldP)
  101. {
  102.     register SpriteLayerPtr        curSpriteLayerP;
  103.     register SpritePtr            curSpriteP;
  104.     Rect                        moveBounds = spriteWorldP->scrollRectMoveBounds;
  105.     
  106.         // Process the sprites
  107.     SWProcessSpriteWorld(spriteWorldP);
  108.     if ( !spriteWorldP->frameHasOccurred )
  109.     {
  110.         return;
  111.     }
  112.  
  113.  
  114.         // Wrap any sprites that have moved outside the scrollRectMoveBounds
  115.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  116.     while (curSpriteLayerP != NULL)
  117.     {
  118.         curSpriteP = curSpriteLayerP->headSpriteP;
  119.  
  120.         while (curSpriteP != NULL)
  121.         {            
  122.                 // Wrap left or right
  123.             if (curSpriteP->destFrameRect.left >= moveBounds.right)
  124.             {
  125.                 curSpriteP->destFrameRect.left -= moveBounds.right;
  126.                 curSpriteP->destFrameRect.right -= moveBounds.right;
  127.             }
  128.             else if (curSpriteP->destFrameRect.left < moveBounds.left)
  129.             {
  130.                 curSpriteP->destFrameRect.left += moveBounds.right;
  131.                 curSpriteP->destFrameRect.right += moveBounds.right;
  132.             }
  133.             
  134.                 // Wrap up or down
  135.             if (curSpriteP->destFrameRect.top >= moveBounds.bottom)
  136.             {
  137.                 curSpriteP->destFrameRect.top -= moveBounds.bottom;
  138.                 curSpriteP->destFrameRect.bottom -= moveBounds.bottom;
  139.             }
  140.             else if (curSpriteP->destFrameRect.top < moveBounds.top)
  141.             {
  142.                 curSpriteP->destFrameRect.top += moveBounds.bottom;
  143.                 curSpriteP->destFrameRect.bottom += moveBounds.bottom;
  144.             }
  145.             
  146.             curSpriteP = curSpriteP->nextSpriteP;
  147.         }
  148.         
  149.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
  150.     }
  151.     
  152.     
  153.         // Call the scrolling world move proc
  154.     if (spriteWorldP->worldMoveProc != NULL)
  155.     {
  156.         (*spriteWorldP->worldMoveProc)(spriteWorldP, spriteWorldP->followSpriteP);
  157.     }
  158.     
  159.     
  160.         // Move visScrollRect
  161.     if (spriteWorldP->horizScrollDelta || spriteWorldP->vertScrollDelta)
  162.     {
  163.         SWOffsetCircularVisScrollRect(spriteWorldP, 
  164.             spriteWorldP->horizScrollDelta, 
  165.             spriteWorldP->vertScrollDelta);
  166.     }
  167. }
  168.  
  169.  
  170.     // Variables shared by SWAnimateCircularSpriteWorld and SWErasePieceOfSprite.
  171.     // These keep track of the vert and horiz scroll rect offset from the previous frame.
  172. short    gOldVertScrollRectOffset, gOldHorizScrollRectOffset;
  173.  
  174.     // Variables shared by SWAnimateCircularSpriteWorld and SWDrawTilesInWrappedRect.
  175.     // These store the original values of the named variables, so the named variables can
  176.     // temporarily be changed and restored.
  177. short    gTempHorizScrollRectOffset, gTempVertScrollRectOffset;
  178. short    gTempOldVertScrollRectOffset, gTempOldHorizScrollRectOffset;
  179.  
  180.  
  181. ///--------------------------------------------------------------------------------------
  182. //    SWAnimateCircularSpriteWorld
  183. ///--------------------------------------------------------------------------------------
  184.  
  185. SW_FUNC void SWAnimateCircularSpriteWorld(
  186.     SpriteWorldPtr spriteWorldP)
  187. {
  188.     UpdateRectStructPtr            curRectStructP,
  189.                                 nextRectStructP;
  190.     register SpriteLayerPtr     curSpriteLayerP;
  191.     register SpritePtr             curSpriteP;
  192.     Rect                        *moveBounds = &spriteWorldP->scrollRectMoveBounds;
  193.     Rect                        rectA, rectB, rectC, rectD, tempDstRect;
  194.     Boolean                        horizClip, vertClip;
  195.  
  196.     SW_ASSERT(spriteWorldP != NULL);
  197.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  198.     SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
  199.     SW_ASSERT(spriteWorldP->windowFrameP->isFrameLocked);
  200.     
  201.     if (!spriteWorldP->frameHasOccurred)
  202.         return;
  203.         
  204.     
  205.         // Add the deadSpriteLayer if there are any Sprites in it.
  206.     if ( spriteWorldP->deadSpriteLayerP->headSpriteP != NULL )
  207.     {
  208.         SWAddSpriteLayer(spriteWorldP, spriteWorldP->deadSpriteLayerP);
  209.     }
  210.     
  211.     
  212.     gOldVertScrollRectOffset = spriteWorldP->backRect.bottom * 
  213.         (spriteWorldP->oldVisScrollRect.top / spriteWorldP->backRect.bottom);
  214.     
  215.     gOldHorizScrollRectOffset = spriteWorldP->backRect.right *
  216.         (spriteWorldP->oldVisScrollRect.left / spriteWorldP->backRect.right);
  217.     
  218.     gTempHorizScrollRectOffset = spriteWorldP->horizScrollRectOffset;
  219.     gTempVertScrollRectOffset = spriteWorldP->vertScrollRectOffset;
  220.     gTempOldVertScrollRectOffset = gOldVertScrollRectOffset;
  221.     gTempOldHorizScrollRectOffset = gOldHorizScrollRectOffset;
  222.  
  223.  
  224.         // Set the port to the work area so we can draw in it
  225.     SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  226.     
  227.     
  228.         // Update the tiles as we scroll
  229.     SWDrawTilesInCircularScrollRect(spriteWorldP);
  230.  
  231.  
  232.     //-----------------erase the sprites--------------------
  233.     
  234.     rectA = spriteWorldP->oldVisScrollRect;
  235.     
  236.         // Wrap right side to the left
  237.     if (rectA.right > moveBounds->right)
  238.     {
  239.         rectB.top = rectA.top;
  240.         rectB.bottom = rectA.bottom;
  241.         rectB.left = moveBounds->left;
  242.         rectB.right = rectA.right - moveBounds->right;
  243.         
  244.         rectA.right = moveBounds->right;
  245.         horizClip = true;
  246.     }
  247.     else
  248.         horizClip = false;
  249.     
  250.     
  251.         // Wrap bottom side to the top
  252.     if (rectA.bottom > moveBounds->bottom)
  253.     {
  254.         rectC.left = rectA.left;
  255.         rectC.right = rectA.right;
  256.         rectC.top = moveBounds->top;
  257.         rectC.bottom = rectA.bottom - moveBounds->bottom;
  258.         
  259.         rectA.bottom = moveBounds->bottom;
  260.         rectB.bottom = moveBounds->bottom;;
  261.         vertClip = true;
  262.     }
  263.     else
  264.         vertClip = false;
  265.         
  266.         
  267.     SWEraseSpritesInRect(spriteWorldP, &rectA);
  268.     
  269.     if (horizClip)
  270.     {
  271.         gOldHorizScrollRectOffset = 0;  // Draw the sprites at the left of the world
  272.         SWEraseSpritesInRect(spriteWorldP, &rectB);
  273.         gOldHorizScrollRectOffset = gTempOldHorizScrollRectOffset;
  274.     }
  275.     
  276.     if (vertClip)
  277.     { 
  278.         gOldVertScrollRectOffset = 0;    // Draw the sprites at the top of the world
  279.         SWEraseSpritesInRect(spriteWorldP, &rectC);
  280.         gOldVertScrollRectOffset = gTempOldVertScrollRectOffset;
  281.     }
  282.     
  283.         // Wrap the corner piece
  284.     if (vertClip && horizClip)
  285.     {
  286.         rectD.left = rectB.left;
  287.         rectD.right = rectB.right;
  288.         rectD.top = rectC.top;
  289.         rectD.bottom = rectC.bottom;
  290.          
  291.         gOldVertScrollRectOffset = 0;        // Draw the sprites at the top of the world
  292.         gOldHorizScrollRectOffset = 0;        // Draw the sprites at the left of the world
  293.         
  294.         SWEraseSpritesInRect(spriteWorldP, &rectD);
  295.  
  296.         gOldHorizScrollRectOffset = gTempOldHorizScrollRectOffset;
  297.         gOldVertScrollRectOffset = gTempOldVertScrollRectOffset;
  298.     }
  299.     
  300.     
  301.         // update flagged background rects
  302.     curRectStructP = spriteWorldP->headUpdateRectP;
  303.     while ( curRectStructP != NULL )
  304.     {
  305.         tempDstRect = curRectStructP->updateRect;
  306.         
  307.             // Make the rect local to the offscreen area
  308.         tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  309.         tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  310.         tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  311.         tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  312.         
  313.             // We're not really erasing a sprite, just copying while wrapping
  314.         SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
  315.         curRectStructP = curRectStructP->nextRectStructP;
  316.     }
  317.     
  318.         // Call the postEraseCallBack
  319.     if (spriteWorldP->postEraseCallBack != NULL)
  320.         (*spriteWorldP->postEraseCallBack)(spriteWorldP);
  321.  
  322.     
  323.     
  324.     //-----------------draw the sprites-------------------
  325.     
  326.     rectA = spriteWorldP->visScrollRect;
  327.     
  328.         // wrap right side to the left
  329.     if (rectA.right > moveBounds->right)
  330.     {
  331.         rectB.top = rectA.top;
  332.         rectB.bottom = rectA.bottom;
  333.         rectB.left = moveBounds->left;
  334.         rectB.right = rectA.right - moveBounds->right;
  335.         
  336.         rectA.right = moveBounds->right;
  337.         horizClip = true;
  338.     }
  339.     else
  340.         horizClip = false;
  341.     
  342.     
  343.         // Wrap bottom side to the top
  344.     if (rectA.bottom > moveBounds->bottom)
  345.     {
  346.         rectC.left = rectA.left;
  347.         rectC.right = rectA.right;
  348.         rectC.top = moveBounds->top;
  349.         rectC.bottom = rectA.bottom - moveBounds->bottom;
  350.         
  351.         rectA.bottom = moveBounds->bottom;
  352.         rectB.bottom = moveBounds->bottom;
  353.         vertClip = true;
  354.     }
  355.     else
  356.         vertClip = false;
  357.     
  358.     
  359.     SWDrawSpritesInRect(spriteWorldP, &rectA);
  360.     
  361.     if (horizClip)
  362.     {
  363.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the sprites at the left of the world
  364.         SWDrawSpritesInRect(spriteWorldP, &rectB);
  365.         spriteWorldP->horizScrollRectOffset = gTempHorizScrollRectOffset;
  366.     }
  367.     
  368.     if (vertClip)
  369.     {
  370.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the sprites at the top of the world
  371.         SWDrawSpritesInRect(spriteWorldP, &rectC);
  372.         spriteWorldP->vertScrollRectOffset = gTempVertScrollRectOffset;
  373.     }
  374.     
  375.         // Wrap the corner piece
  376.     if (vertClip && horizClip)
  377.     {
  378.         rectD.left = rectB.left;
  379.         rectD.right = rectB.right;
  380.         rectD.top = rectC.top;
  381.         rectD.bottom = rectC.bottom;
  382.         
  383.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the sprites at the left of the world
  384.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the sprites at the top of the world
  385.         
  386.         SWDrawSpritesInRect(spriteWorldP, &rectD);
  387.         
  388.         spriteWorldP->vertScrollRectOffset = gTempVertScrollRectOffset;
  389.         spriteWorldP->horizScrollRectOffset = gTempHorizScrollRectOffset;
  390.     }
  391.     
  392.     
  393.         // Clean up //
  394.         
  395.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  396.  
  397.         // iterate through the layers in this world
  398.     while (curSpriteLayerP != NULL)
  399.     {
  400.         curSpriteP = curSpriteLayerP->headSpriteP;
  401.  
  402.             // iterate through the sprites in this layer
  403.         while (curSpriteP != NULL)
  404.         {
  405.                 // Set last rect to current rect
  406.             curSpriteP->oldFrameRect = curSpriteP->destFrameRect;
  407.             
  408.             curSpriteP->needsToBeDrawn = false;
  409.             curSpriteP->needsToBeErased = false;
  410.  
  411.             curSpriteP = curSpriteP->nextSpriteP;
  412.         }
  413.         
  414.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
  415.     }
  416.     
  417.     spriteWorldP->oldVisScrollRect = spriteWorldP->visScrollRect;
  418.     
  419.     
  420.         // Call the postDrawCallBack
  421.     if (spriteWorldP->postDrawCallBack != NULL)
  422.         (*spriteWorldP->postDrawCallBack)(spriteWorldP);
  423.     
  424.     
  425.     //-----------------update the screen--------------------
  426.     
  427.         // Set the port to the window
  428.     SetGWorld(spriteWorldP->windowFrameP->framePort, nil);
  429.     
  430.     if (spriteWorldP->usingVBL)
  431.     {  
  432.         spriteWorldP->vblTaskRec.hasVBLFired = false;
  433.         while ( !spriteWorldP->vblTaskRec.hasVBLFired )
  434.         {}
  435.     }
  436.     
  437.         // Copy offscreen area to screen while wrapping
  438.     SWWrapWorldToScreen(spriteWorldP);
  439.     
  440.     
  441.         // dispose of flagged background rects
  442.     nextRectStructP = spriteWorldP->headUpdateRectP;
  443.     while ( nextRectStructP != NULL )
  444.     {
  445.         curRectStructP = nextRectStructP;
  446.         nextRectStructP = curRectStructP->nextRectStructP;
  447.         DisposePtr( (Ptr)curRectStructP );
  448.     }
  449.     spriteWorldP->headUpdateRectP = NULL;
  450.     
  451.     spriteWorldP->numTilesChanged = 0;
  452.     
  453.     
  454.         // Remove the deadSpriteLayer if we added it earlier.
  455.     if ( spriteWorldP->deadSpriteLayerP->headSpriteP != NULL )
  456.     {
  457.         SWRemoveSpriteLayer(spriteWorldP, spriteWorldP->deadSpriteLayerP);
  458.     }
  459. }
  460.  
  461.  
  462. #pragma mark -
  463. ///--------------------------------------------------------------------------------------
  464. //  SWDrawTilesInCircularScrollRect - called by SWAnimateCircularSpriteWorld to update
  465. //    the portion of the visScrollRect that just scrolled into view.
  466. ///--------------------------------------------------------------------------------------
  467.  
  468. void SWDrawTilesInCircularScrollRect(
  469.     SpriteWorldPtr    spriteWorldP)
  470. {
  471.     Rect        tempDstRect;
  472.     short        distA, distB;
  473.     short        hScrollDelta, vScrollDelta;
  474.     
  475.         // Calculate the scrollDelta of the visScrollRect. Since it maybe have
  476.         // wrapped around since the previous frame, we must go through some extra
  477.         // hoops to make sure we calculate the delta correctly.
  478.     distA = spriteWorldP->visScrollRect.left - spriteWorldP->oldVisScrollRect.left;
  479.     if (distA < 0)    // if (visScrollRect.left < oldVisScrollRect.left)
  480.         distB = distA + spriteWorldP->scrollRectMoveBounds.right;
  481.     else
  482.         distB = distA - spriteWorldP->scrollRectMoveBounds.right;
  483.     
  484.     if ( SW_ABS(distB) < SW_ABS(distA) )
  485.         hScrollDelta = distB;
  486.     else
  487.         hScrollDelta = distA;
  488.     
  489.         // Do the same for the vScrollDelta...
  490.     distA = spriteWorldP->visScrollRect.top - spriteWorldP->oldVisScrollRect.top;
  491.     if (distA < 0)    // if (visScrollRect.top < oldVisScrollRect.top)
  492.         distB = distA + spriteWorldP->scrollRectMoveBounds.bottom;
  493.     else
  494.         distB = distA - spriteWorldP->scrollRectMoveBounds.bottom;
  495.     
  496.     if ( SW_ABS(distB) < SW_ABS(distA) )
  497.         vScrollDelta = distB;
  498.     else
  499.         vScrollDelta = distA;
  500.     
  501.     
  502.         // Update tiles as we scroll if tiling is turned on
  503.     if (spriteWorldP->tilingIsOn)
  504.     {
  505.             // VisScrollRect moved horizontally
  506.         if (hScrollDelta)
  507.         {
  508.                 // Get rect of new vertical section to update
  509.             tempDstRect = spriteWorldP->visScrollRect;
  510.                 
  511.             if (hScrollDelta < 0)
  512.                 tempDstRect.right = tempDstRect.left - hScrollDelta;    // Moved left
  513.             else    
  514.                 tempDstRect.left = tempDstRect.right - hScrollDelta;    // Moved right
  515.     
  516.             SWDrawTilesInWrappedRect(spriteWorldP, &tempDstRect, true);
  517.             
  518.             
  519.                 // Did VisScrollRect moved diagonally?
  520.             if (vScrollDelta)
  521.             {
  522.                     // Get rect of new horizontal section to update
  523.                 tempDstRect = spriteWorldP->visScrollRect;
  524.                 
  525.                 if (vScrollDelta < 0)
  526.                     tempDstRect.bottom = tempDstRect.top - vScrollDelta;    // Moved up
  527.                 else    
  528.                     tempDstRect.top = tempDstRect.bottom - vScrollDelta;    // Moved down
  529.                 
  530.                     // Clip off the part we've already updated
  531.                 if (hScrollDelta < 0)
  532.                     tempDstRect.left -= hScrollDelta;
  533.                 else    
  534.                     tempDstRect.right -= hScrollDelta;
  535.                 
  536.                     // We pass false here to avoid a bug which occured in the
  537.                     // tile optimizing code when updating tiles twice in one frame
  538.                 if (tempDstRect.right > tempDstRect.left)
  539.                 {
  540.                     SWDrawTilesInWrappedRect(spriteWorldP, &tempDstRect, false);
  541.                 }
  542.             }
  543.         }    // VisScrollRect moved vertically only (not diagonally)
  544.         else if (vScrollDelta)
  545.         {
  546.                 // Get rect of new horizontal section to update
  547.             tempDstRect = spriteWorldP->visScrollRect;
  548.             
  549.             if (vScrollDelta < 0)
  550.                 tempDstRect.bottom = tempDstRect.top - vScrollDelta;    // Moved up
  551.             else    
  552.                 tempDstRect.top = tempDstRect.bottom - vScrollDelta;    // Moved down
  553.  
  554.             SWDrawTilesInWrappedRect(spriteWorldP, &tempDstRect, true);
  555.         }
  556.     }
  557. }
  558.  
  559. ///--------------------------------------------------------------------------------------
  560. //  SWDrawTilesInWrappedRect - called by SWDrawTilesInCircularScrollRect. This function
  561. //    draws the tiles in the rect, while wrapping the rect around the circular world's
  562. //    bounds if it is hanging off the edge of the circular world.
  563. ///--------------------------------------------------------------------------------------
  564.  
  565. void SWDrawTilesInWrappedRect(
  566.     SpriteWorldPtr    spriteWorldP,
  567.     Rect*            tempDstRectP,
  568.     Boolean            optimizingMode)
  569. {
  570.     Rect*        backRectP = &spriteWorldP->scrollRectMoveBounds;
  571.     Rect        rectA, rectB, rectC, rectD;
  572.     Boolean        horizClip, vertClip;
  573.     
  574.     
  575.     rectA = *tempDstRectP;
  576.  
  577.     
  578.         // Clip and wrap left or right side
  579.     if (rectA.right > backRectP->right)
  580.     {
  581.             // wrap right side to the left
  582.         rectB = rectA;
  583.         
  584.         if (rectB.left < backRectP->right)
  585.             rectB.left = backRectP->right;
  586.         
  587.         rectB.left -= backRectP->right;
  588.         rectB.right -= backRectP->right;
  589.         
  590.         rectA.right = backRectP->right;
  591.         horizClip = true;
  592.     }
  593.     else
  594.         horizClip = false;
  595.     
  596.     
  597.     if (rectA.bottom > backRectP->bottom)
  598.     {
  599.             // wrap bottom side to the top
  600.         rectC = rectA;
  601.  
  602.         if (rectC.top < backRectP->bottom)
  603.             rectC.top = backRectP->bottom;
  604.         
  605.         rectC.top -= backRectP->bottom;
  606.         rectC.bottom -= backRectP->bottom;
  607.         
  608.         rectA.bottom = backRectP->bottom;
  609.         rectB.bottom = backRectP->bottom;
  610.         vertClip = true;
  611.     }
  612.     else
  613.         vertClip = false;
  614.     
  615.     
  616.     if ( (rectA.bottom > rectA.top) && (rectA.right > rectA.left) )
  617.     {
  618.         (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectA, optimizingMode);
  619.         SWWrapRectToWorkArea(spriteWorldP, &rectA);
  620.     }
  621.     
  622.     if (horizClip)
  623.     {
  624.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the tiles at the left of the world
  625.         
  626.         if ( (rectB.bottom > rectB.top) && (rectB.right > rectB.left) )
  627.         {
  628.             (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectB, optimizingMode);
  629.             SWWrapRectToWorkArea(spriteWorldP, &rectB);
  630.         }
  631.         
  632.         spriteWorldP->horizScrollRectOffset = gTempHorizScrollRectOffset;
  633.     }
  634.     
  635.     if (vertClip)
  636.     {
  637.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the tiles at the top of the world
  638.         
  639.         if ( (rectC.bottom > rectC.top) && (rectC.right > rectC.left) )
  640.         {
  641.             (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectC, optimizingMode);
  642.             SWWrapRectToWorkArea(spriteWorldP, &rectC);
  643.         }
  644.         
  645.         spriteWorldP->vertScrollRectOffset = gTempVertScrollRectOffset;
  646.     }
  647.  
  648.         // Wrap the corner piece
  649.     if (vertClip && horizClip)
  650.     {
  651.         rectD.left = rectB.left;
  652.         rectD.right = rectB.right;
  653.         rectD.top = rectC.top;
  654.         rectD.bottom = rectC.bottom;
  655.         
  656.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the tiles at the left of the world
  657.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the tiles at the top of the world
  658.         
  659.         if ( (rectD.bottom > rectD.top) && (rectD.right > rectD.left) )
  660.         {
  661.             (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectD, optimizingMode);
  662.             SWWrapRectToWorkArea(spriteWorldP, &rectD);
  663.         }
  664.         
  665.         spriteWorldP->vertScrollRectOffset = gTempVertScrollRectOffset;
  666.         spriteWorldP->horizScrollRectOffset = gTempHorizScrollRectOffset;
  667.     }
  668. }
  669.     
  670.  
  671. ///--------------------------------------------------------------------------------------
  672. //  SWEraseSpritesInRect - this is called up to four times by SWAnimateCircularSpriteWorld,
  673. //    since that function clips the visScrollRect with the scrollingWorldMoveBounds.
  674. //    Whenever that rectangle is clipped, the sprites are erased in each piece. This is
  675. //    what allows the sprites to wrap around the world, even when they're half on one side
  676. //    of the world and half on another side.
  677. //
  678. //    This function also handles the drawing of tiles in the updateRect as we scroll.
  679. ///--------------------------------------------------------------------------------------
  680.  
  681. void SWEraseSpritesInRect(
  682.     SpriteWorldPtr    spriteWorldP,
  683.     Rect*            updateRectP)
  684. {
  685.     register SpriteLayerPtr     curSpriteLayerP;
  686.     register SpritePtr             curSpriteP;
  687.     short                        curTileLayer;
  688.     Rect                        dstRectA, dstRectB, dstRectC, dstRectD;
  689.     short                        rightClip, bottomClip;
  690.     
  691.     
  692.     //-----------------erase the sprites--------------------
  693.     
  694.     
  695.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  696.     curTileLayer = 0;
  697.  
  698.         // iterate through the layers in this world
  699.     while (curSpriteLayerP != NULL)
  700.     {
  701.         curSpriteP = curSpriteLayerP->headSpriteP;
  702.         
  703.         if (curSpriteLayerP->tileLayer > curTileLayer)
  704.             curTileLayer = curSpriteLayerP->tileLayer;
  705.  
  706.             // iterate through the sprites in this layer
  707.         while (curSpriteP != NULL)
  708.         {
  709.             SW_ASSERT(curSpriteP->curFrameP->isFrameLocked);
  710.             curSpriteP->tileDepth = curTileLayer;
  711.             
  712.             if (curSpriteP->isVisible)
  713.             {
  714.                 dstRectA = curSpriteP->oldFrameRect;
  715.                 
  716.                 // Here we clip the sprite with the circular world's right and bottom sides. 
  717.                 // Then we clip each piece with the updateRectP and draw it.
  718.  
  719.                     // clip off the bottom
  720.                 if (dstRectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
  721.                 {
  722.                     bottomClip = dstRectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
  723.                     dstRectA.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
  724.                 }
  725.                 else
  726.                     bottomClip = 0;
  727.                 
  728.                     // clip off the right
  729.                 if (dstRectA.right > spriteWorldP->scrollRectMoveBounds.right)
  730.                 {
  731.                     rightClip = dstRectA.right - spriteWorldP->scrollRectMoveBounds.right;
  732.                     dstRectA.right = spriteWorldP->scrollRectMoveBounds.right;
  733.                 }
  734.                 else
  735.                     rightClip = 0;
  736.                 
  737.                 
  738.                     // First erase the main piece of the sprite
  739.                 SWErasePieceOfSprite(spriteWorldP, updateRectP, &dstRectA);
  740.  
  741.                 if (bottomClip)    // Wrap bottom piece to top
  742.                 {
  743.                     dstRectB.right = dstRectA.right;
  744.                     dstRectB.left = dstRectA.left;
  745.                     dstRectB.top = spriteWorldP->scrollRectMoveBounds.top;
  746.                     dstRectB.bottom = spriteWorldP->scrollRectMoveBounds.top + bottomClip;
  747.                     
  748.                     SWErasePieceOfSprite(spriteWorldP, updateRectP, &dstRectB);
  749.                 }
  750.                 
  751.                 if (rightClip)        // Wrap right piece to the left
  752.                 {
  753.                     dstRectC.top = dstRectA.top;
  754.                     dstRectC.bottom = dstRectA.bottom;
  755.                     dstRectC.left = spriteWorldP->scrollRectMoveBounds.left;
  756.                     dstRectC.right = spriteWorldP->scrollRectMoveBounds.left + rightClip;
  757.                     
  758.                     SWErasePieceOfSprite(spriteWorldP, updateRectP, &dstRectC);
  759.                 }
  760.                 
  761.                     // If there is a corner piece, wrap it too.
  762.                 if (rightClip && bottomClip)
  763.                 {
  764.                     dstRectD.top = dstRectB.top;
  765.                     dstRectD.bottom = dstRectB.bottom;
  766.                     dstRectD.left = dstRectC.left;
  767.                     dstRectD.right = dstRectC.right;
  768.                     
  769.                     SWErasePieceOfSprite(spriteWorldP, updateRectP, &dstRectD);
  770.                 }
  771.             }
  772.             
  773.             curSpriteP = curSpriteP->nextSpriteP;
  774.         }
  775.         
  776.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
  777.     }
  778. }
  779.  
  780.  
  781. ///--------------------------------------------------------------------------------------
  782. //  SWDrawSpritesInRect - this is called up to four times by SWAnimateCircularSpriteWorld,
  783. //    since that function clips the visScrollRect with the scrollingWorldMoveBounds.
  784. //    Whenever that rectangle is clipped, the sprites are drawn in each piece. This is
  785. //    what allows the sprites to wrap around the world, even when they're half on one side
  786. //    of the world and half on another side.
  787. ///--------------------------------------------------------------------------------------
  788.  
  789. void SWDrawSpritesInRect(
  790.     SpriteWorldPtr    spriteWorldP,
  791.     Rect*            updateRectP)
  792. {
  793.     register SpriteLayerPtr     curSpriteLayerP;
  794.     register SpritePtr             curSpriteP;
  795.     Rect                        srcRectA, srcRectB, srcRectC, srcRectD;
  796.     Rect                        dstRectA, dstRectB, dstRectC, dstRectD;
  797.     short                        rightClip, bottomClip;
  798.  
  799.     
  800.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  801.  
  802.         // iterate through the layers in this world
  803.     while (curSpriteLayerP != NULL)
  804.     {
  805.         curSpriteP = curSpriteLayerP->headSpriteP;
  806.  
  807.             // iterate through the sprites in this layer
  808.         while (curSpriteP != NULL)
  809.         {
  810.             if (curSpriteP->isVisible)
  811.             {
  812.                 srcRectA = curSpriteP->curFrameP->frameRect;
  813.                 dstRectA = curSpriteP->destFrameRect;
  814.                 
  815.                     // Here we clip the sprite with the circular world's bounds. Then
  816.                     // we clip each piece with the updateRectP and draw it.
  817.                 
  818.                     // clip off the bottom
  819.                 if (dstRectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
  820.                 {
  821.                     bottomClip = dstRectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
  822.                     dstRectA.bottom -= bottomClip;
  823.                     srcRectA.bottom -= bottomClip;
  824.                 }
  825.                 else
  826.                     bottomClip = 0;
  827.                 
  828.                     // clip off the right
  829.                 if (dstRectA.right > spriteWorldP->scrollRectMoveBounds.right)
  830.                 {
  831.                     rightClip = dstRectA.right - spriteWorldP->scrollRectMoveBounds.right;
  832.                     dstRectA.right -= rightClip;
  833.                     srcRectA.right -= rightClip;
  834.                 }
  835.                 else
  836.                     rightClip = 0;
  837.                 
  838.                     // First draw the main piece of the sprite
  839.                 SWDrawPieceOfSprite(spriteWorldP, updateRectP, curSpriteP, 
  840.                         &srcRectA, &dstRectA);
  841.                 
  842.                     // Now we wrap any pieces that are hanging off the border of
  843.                     // the circular scrolling world. (Which were clipped above.)
  844.  
  845.                 if (bottomClip)        // Wrap bottom piece to top
  846.                 {
  847.                     dstRectB.right = dstRectA.right;
  848.                     dstRectB.left = dstRectA.left;
  849.                     dstRectB.top = spriteWorldP->scrollRectMoveBounds.top;
  850.                     dstRectB.bottom = spriteWorldP->scrollRectMoveBounds.top + bottomClip;
  851.                     
  852.                     srcRectB = srcRectA;
  853.                     srcRectB.bottom += bottomClip; 
  854.                     srcRectB.top += SW_RECT_HEIGHT(dstRectA);
  855.                     
  856.                     SWDrawPieceOfSprite(spriteWorldP, updateRectP, curSpriteP, 
  857.                         &srcRectB, &dstRectB);
  858.                 }
  859.                 
  860.                 if (rightClip)        // Wrap right piece to the left
  861.                 {
  862.                     dstRectC.top = dstRectA.top;
  863.                     dstRectC.bottom = dstRectA.bottom;
  864.                     dstRectC.left = spriteWorldP->scrollRectMoveBounds.left;
  865.                     dstRectC.right = spriteWorldP->scrollRectMoveBounds.left + rightClip;
  866.                     
  867.                     srcRectC = srcRectA;
  868.                     srcRectC.right += rightClip; 
  869.                     srcRectC.left += SW_RECT_WIDTH(dstRectA);
  870.                     
  871.                     SWDrawPieceOfSprite(spriteWorldP, updateRectP, curSpriteP, 
  872.                         &srcRectC, &dstRectC);
  873.                 }
  874.                 
  875.                     // If there is a corner piece, wrap it too.
  876.                 if (rightClip && bottomClip)
  877.                 {
  878.                     dstRectD.top = dstRectB.top;
  879.                     dstRectD.bottom = dstRectB.bottom;
  880.                     dstRectD.left = dstRectC.left;
  881.                     dstRectD.right = dstRectC.right;
  882.                     
  883.                     srcRectD.top = srcRectB.top;
  884.                     srcRectD.bottom = srcRectB.bottom;
  885.                     srcRectD.left = srcRectC.left;
  886.                     srcRectD.right = srcRectC.right;
  887.                     
  888.                     SWDrawPieceOfSprite(spriteWorldP, updateRectP, curSpriteP, 
  889.                         &srcRectD, &dstRectD);
  890.                 }
  891.             }
  892.             
  893.             curSpriteP = curSpriteP->nextSpriteP;
  894.         }
  895.         
  896.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
  897.     }
  898. }
  899.  
  900.  
  901. ///--------------------------------------------------------------------------------------
  902. //  SWErasePieceOfSprite
  903. ///--------------------------------------------------------------------------------------
  904.                 
  905. void SWErasePieceOfSprite(
  906.     SpriteWorldPtr    spriteWorldP,
  907.     Rect*            updateRectP,
  908.     Rect*            dstRectP)
  909. {
  910.     Rect    dstRect = *dstRectP;
  911.     short    temp;
  912.     
  913.         // Clip the sprite with this portion of the visScrollRect
  914.     if (dstRect.top < updateRectP->top)
  915.         dstRect.top = updateRectP->top;
  916.     
  917.     if (dstRect.bottom > updateRectP->bottom)
  918.         dstRect.bottom = updateRectP->bottom;
  919.     
  920.     if (dstRect.left < updateRectP->left)
  921.         dstRect.left = updateRectP->left;
  922.     
  923.     if (dstRect.right > updateRectP->right)
  924.         dstRect.right = updateRectP->right;
  925.     
  926.     
  927.         // Is the sprite visible in this rect?
  928.     if ( (dstRect.right > dstRect.left) && (dstRect.bottom > dstRect.top) )
  929.     {
  930.             // Make the sprite's rect local to the offscreen area
  931.         dstRect.top -= gOldVertScrollRectOffset;
  932.         dstRect.bottom -= gOldVertScrollRectOffset;
  933.         dstRect.left -= gOldHorizScrollRectOffset;
  934.         dstRect.right -= gOldHorizScrollRectOffset;
  935.         
  936.             // align the left edge to long word boundary
  937.         dstRect.left &= (spriteWorldP->workFrameP->leftAlignFactor);
  938.         
  939.             // align the right edge to long word boundary
  940.         temp = dstRect.right & spriteWorldP->workFrameP->rightAlignFactor;
  941.             
  942.         if (temp != 0)
  943.             dstRect.right += (spriteWorldP->workFrameP->rightAlignFactor + 1) - temp;
  944.         
  945.         SWEraseWrappedSprite(spriteWorldP, &dstRect);
  946.     }
  947. }
  948.  
  949.  
  950. ///--------------------------------------------------------------------------------------
  951. //  SWDrawPieceOfSprite
  952. ///--------------------------------------------------------------------------------------
  953.                 
  954. void SWDrawPieceOfSprite(
  955.     SpriteWorldPtr    spriteWorldP,
  956.     Rect*            updateRectP,
  957.     SpritePtr        curSpriteP,
  958.     Rect*            srcRectP,
  959.     Rect*            dstRectP)
  960. {
  961.     Rect    srcRect = *srcRectP;
  962.     Rect    dstRect = *dstRectP;
  963.     Rect    tempDstRect;
  964.     
  965.         // Clip the sprite with this portion of the visScrollRect
  966.     if (dstRect.top < updateRectP->top)
  967.     {
  968.         srcRect.top += updateRectP->top - dstRect.top;
  969.         dstRect.top = updateRectP->top;
  970.     }
  971.     
  972.     if (dstRect.bottom > updateRectP->bottom)
  973.     {
  974.         srcRect.bottom += updateRectP->bottom - dstRect.bottom;
  975.         dstRect.bottom = updateRectP->bottom;
  976.     }
  977.     
  978.     if (dstRect.left < updateRectP->left)
  979.     {
  980.         srcRect.left += updateRectP->left - dstRect.left;
  981.         dstRect.left = updateRectP->left;
  982.     }
  983.     
  984.     if (dstRect.right > updateRectP->right)
  985.     {
  986.         srcRect.right += updateRectP->right - dstRect.right;
  987.         dstRect.right = updateRectP->right;
  988.     }
  989.  
  990.     
  991.         // Is the sprite visible in this rect?
  992.     if ( (dstRect.right > dstRect.left) && (dstRect.bottom > dstRect.top) )
  993.     {
  994.         gCurrentSpriteBeingDrawn = curSpriteP;
  995.         
  996.             // Make the sprite's rect local to the offscreen area
  997.         tempDstRect = dstRect;
  998.         tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  999.         tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1000.         tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  1001.         tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  1002.         
  1003.         SWDrawWrappedSprite(curSpriteP, spriteWorldP->workFrameP, &srcRect, &tempDstRect);
  1004.         
  1005.         gCurrentSpriteBeingDrawn = NULL;
  1006.         
  1007.             // Draw tiles above sprite
  1008.         if (spriteWorldP->tilingIsOn &&
  1009.             curSpriteP->tileDepth <= spriteWorldP->lastActiveTileLayer)
  1010.         {
  1011.             SWDrawTilesAboveSprite(spriteWorldP, &dstRect, curSpriteP->tileDepth);
  1012.         }
  1013.     }        
  1014. }
  1015.  
  1016.  
  1017. #pragma mark -
  1018. ///--------------------------------------------------------------------------------------
  1019. //  SWMoveCircularVisScrollRect
  1020. ///--------------------------------------------------------------------------------------
  1021.  
  1022. SW_FUNC void SWMoveCircularVisScrollRect(
  1023.     SpriteWorldPtr    spriteWorldP,
  1024.     short            horizPos,
  1025.     short            vertPos)
  1026. {
  1027.     short    width, height, moveBoundsWidth, moveBoundsHeight;
  1028.     
  1029.     height = spriteWorldP->visScrollRect.bottom - spriteWorldP->visScrollRect.top;
  1030.     width = spriteWorldP->visScrollRect.right - spriteWorldP->visScrollRect.left;
  1031.  
  1032.     spriteWorldP->visScrollRect.top = vertPos;
  1033.     spriteWorldP->visScrollRect.bottom = vertPos + height;
  1034.     spriteWorldP->visScrollRect.left = horizPos;
  1035.     spriteWorldP->visScrollRect.right = horizPos + width;
  1036.     
  1037.     moveBoundsWidth = SW_RECT_WIDTH(spriteWorldP->scrollRectMoveBounds);
  1038.     moveBoundsHeight = SW_RECT_HEIGHT(spriteWorldP->scrollRectMoveBounds);
  1039.     
  1040.         // Wrap visScrollRect if it has moved past the circular world's moveBounds
  1041.     if (spriteWorldP->visScrollRect.top >= spriteWorldP->scrollRectMoveBounds.bottom)
  1042.     {
  1043.         spriteWorldP->visScrollRect.top -= moveBoundsHeight;
  1044.         spriteWorldP->visScrollRect.bottom -= moveBoundsHeight;
  1045.     }
  1046.     else if (spriteWorldP->visScrollRect.top < spriteWorldP->scrollRectMoveBounds.top)
  1047.     {
  1048.         spriteWorldP->visScrollRect.top += moveBoundsHeight;
  1049.         spriteWorldP->visScrollRect.bottom += moveBoundsHeight;
  1050.     }
  1051.     
  1052.     if (spriteWorldP->visScrollRect.left >= spriteWorldP->scrollRectMoveBounds.right)
  1053.     {
  1054.         spriteWorldP->visScrollRect.left -= moveBoundsWidth;
  1055.         spriteWorldP->visScrollRect.right -= moveBoundsWidth;
  1056.     }
  1057.     else if (spriteWorldP->visScrollRect.left < spriteWorldP->scrollRectMoveBounds.left)
  1058.     {
  1059.         spriteWorldP->visScrollRect.left += moveBoundsWidth;
  1060.         spriteWorldP->visScrollRect.right += moveBoundsWidth;
  1061.     }
  1062.  
  1063.     SWCalculateOffscreenScrollRect(spriteWorldP);
  1064. }
  1065.  
  1066.  
  1067. ///--------------------------------------------------------------------------------------
  1068. //  SWOffsetCircularVisScrollRect
  1069. ///--------------------------------------------------------------------------------------
  1070.  
  1071. SW_FUNC void SWOffsetCircularVisScrollRect(
  1072.     SpriteWorldPtr    spriteWorldP,
  1073.     short            horizOffset,
  1074.     short            vertOffset)
  1075. {
  1076.     short    moveBoundsWidth, moveBoundsHeight;
  1077.     
  1078.     spriteWorldP->visScrollRect.top += vertOffset;
  1079.     spriteWorldP->visScrollRect.bottom += vertOffset;
  1080.     spriteWorldP->visScrollRect.left += horizOffset;
  1081.     spriteWorldP->visScrollRect.right += horizOffset;
  1082.     
  1083.     moveBoundsWidth = SW_RECT_WIDTH(spriteWorldP->scrollRectMoveBounds);
  1084.     moveBoundsHeight = SW_RECT_HEIGHT(spriteWorldP->scrollRectMoveBounds);
  1085.  
  1086.         // Wrap visScrollRect if it has moved past the circular world's moveBounds
  1087.     if (spriteWorldP->visScrollRect.top >= spriteWorldP->scrollRectMoveBounds.bottom)
  1088.     {
  1089.         spriteWorldP->visScrollRect.top -= moveBoundsHeight;
  1090.         spriteWorldP->visScrollRect.bottom -= moveBoundsHeight;
  1091.     }
  1092.     else if (spriteWorldP->visScrollRect.top < spriteWorldP->scrollRectMoveBounds.top)
  1093.     {
  1094.         spriteWorldP->visScrollRect.top += moveBoundsHeight;
  1095.         spriteWorldP->visScrollRect.bottom += moveBoundsHeight;
  1096.     }
  1097.     
  1098.     if (spriteWorldP->visScrollRect.left >= spriteWorldP->scrollRectMoveBounds.right)
  1099.     {
  1100.         spriteWorldP->visScrollRect.left -= moveBoundsWidth;
  1101.         spriteWorldP->visScrollRect.right -= moveBoundsWidth;
  1102.     }
  1103.     else if (spriteWorldP->visScrollRect.left < spriteWorldP->scrollRectMoveBounds.left)
  1104.     {
  1105.         spriteWorldP->visScrollRect.left += moveBoundsWidth;
  1106.         spriteWorldP->visScrollRect.right += moveBoundsWidth;
  1107.     }
  1108.  
  1109.     SWCalculateOffscreenScrollRect(spriteWorldP);
  1110. }
  1111.  
  1112.  
  1113. ///--------------------------------------------------------------------------------------
  1114. //    SWCollideCircularSpriteLayer - compares wrapped srcSprite with wrapped dstSprite
  1115. ///--------------------------------------------------------------------------------------
  1116.  
  1117. SW_FUNC void SWCollideCircularSpriteLayer(
  1118.     SpriteWorldPtr spriteWorldP,
  1119.     SpriteLayerPtr srcSpriteLayerP,
  1120.     SpriteLayerPtr dstSpriteLayerP)
  1121. {
  1122.     SpritePtr    srcSpriteP, nextSrcSpriteP;
  1123.     SpritePtr    dstSpriteP, nextDstSpriteP;
  1124.     Rect        sectRect, srcRect[4], dstRect[4];
  1125.     Boolean        srcRectWrapped[4], dstRectWrapped[4];
  1126.     short        srcNum, dstNum, moveBoundsWidth, moveBoundsHeight;
  1127.     
  1128.         // Don't check for collisions unless the frame has been processed!
  1129.     if (!spriteWorldP->frameHasOccurred)
  1130.         return;
  1131.     
  1132.     moveBoundsWidth = SW_RECT_WIDTH(spriteWorldP->scrollRectMoveBounds);
  1133.     moveBoundsHeight = SW_RECT_HEIGHT(spriteWorldP->scrollRectMoveBounds);
  1134.     
  1135.     srcRectWrapped[0] = true;    // These values will always be true
  1136.     dstRectWrapped[0] = true;
  1137.  
  1138.     srcSpriteP = srcSpriteLayerP->headSpriteP;
  1139.  
  1140.         // Cycle through all source Sprites
  1141.     while (srcSpriteP != NULL)
  1142.     {
  1143.             // Skip this sprite if it has no collideProc
  1144.         if (srcSpriteP->spriteCollideProc == NULL)
  1145.         {
  1146.             srcSpriteP = srcSpriteP->nextSpriteP;
  1147.             continue;
  1148.         }
  1149.         
  1150.         dstSpriteP = dstSpriteLayerP->headSpriteP;
  1151.         nextSrcSpriteP = srcSpriteP->nextSpriteP;
  1152.         srcRect[0] = srcSpriteP->destFrameRect;
  1153.         
  1154.         //-----------------------Clip the source sprite-----------------------
  1155.         
  1156.             // Keeps track of which rects were given values
  1157.         srcRectWrapped[1] = srcRectWrapped[2] = srcRectWrapped[3] = false;
  1158.  
  1159.             // Wrap bottom piece to the top //
  1160.         if (srcRect[0].bottom > spriteWorldP->scrollRectMoveBounds.bottom)
  1161.         {
  1162.             srcRect[1].top = srcRect[0].top - moveBoundsHeight;
  1163.             srcRect[1].bottom = srcRect[0].bottom - moveBoundsHeight;
  1164.             srcRect[1].left = srcRect[0].left;
  1165.             srcRect[1].right = srcRect[0].right;
  1166.             srcRectWrapped[1] = true;
  1167.         }
  1168.         
  1169.             // Wrap right piece to the left //
  1170.         if (srcRect[0].right > spriteWorldP->scrollRectMoveBounds.right)
  1171.         {
  1172.             srcRect[2].top = srcRect[0].top;
  1173.             srcRect[2].bottom = srcRect[0].bottom;
  1174.             srcRect[2].left = srcRect[0].left - moveBoundsWidth;
  1175.             srcRect[2].right = srcRect[0].right - moveBoundsWidth;
  1176.             srcRectWrapped[2] = true;
  1177.         }
  1178.         
  1179.             // Wrap bottom-right piece to upper left corner //
  1180.         if (srcRectWrapped[1] && srcRectWrapped[2])
  1181.         {
  1182.             srcRect[3].top = srcRect[1].top;
  1183.             srcRect[3].bottom = srcRect[1].bottom;
  1184.             srcRect[3].left = srcRect[2].left;
  1185.             srcRect[3].right = srcRect[2].right;
  1186.             srcRectWrapped[3] = true;
  1187.         }
  1188.     
  1189.             // Cycle through all dest Sprites
  1190.         while (dstSpriteP != NULL)
  1191.         {
  1192.             nextDstSpriteP = dstSpriteP->nextSpriteP;
  1193.             dstRect[0] = dstSpriteP->destFrameRect;
  1194.             
  1195.             //-----------------------Clip the dest sprite-----------------------
  1196.             
  1197.             if (srcSpriteP != dstSpriteP)
  1198.             {
  1199.                     // Keeps track of which rects were given values
  1200.                 dstRectWrapped[1] = dstRectWrapped[2] = dstRectWrapped[3] = false;
  1201.  
  1202.                     // Wrap bottom piece to the top //
  1203.                 if (dstRect[0].bottom > spriteWorldP->scrollRectMoveBounds.bottom)
  1204.                 {
  1205.                     dstRect[1].top = dstRect[0].top - moveBoundsHeight;
  1206.                     dstRect[1].bottom = dstRect[0].bottom - moveBoundsHeight;
  1207.                     dstRect[1].left = dstRect[0].left;
  1208.                     dstRect[1].right = dstRect[0].right;
  1209.                     dstRectWrapped[1] = true;
  1210.                 }
  1211.                 
  1212.                     // Wrap right piece to the left //
  1213.                 if (dstRect[0].right > spriteWorldP->scrollRectMoveBounds.right)
  1214.                 {
  1215.                     dstRect[2].top = dstRect[0].top;
  1216.                     dstRect[2].bottom = dstRect[0].bottom;
  1217.                     dstRect[2].left = dstRect[0].left - moveBoundsWidth;
  1218.                     dstRect[2].right = dstRect[0].right - moveBoundsWidth;
  1219.                     dstRectWrapped[2] = true;
  1220.                 }
  1221.                 
  1222.                     // Wrap bottom-right piece to upper left corner //
  1223.                 if (dstRectWrapped[1] && dstRectWrapped[2])
  1224.                 {
  1225.                     dstRect[3].top = dstRect[1].top;
  1226.                     dstRect[3].bottom = dstRect[1].bottom;
  1227.                     dstRect[3].left = dstRect[2].left;
  1228.                     dstRect[3].right = dstRect[2].right;
  1229.                     dstRectWrapped[3] = true;
  1230.                 }
  1231.             
  1232.  
  1233.                     // Check for overlapping rects (compare each dstRect with each srcRect)
  1234.                 for (srcNum = 0; srcNum <= 3; srcNum++)
  1235.                 {
  1236.                     if (srcRectWrapped[srcNum] == false)
  1237.                         continue;
  1238.                     
  1239.                     for (dstNum = 0; dstNum <= 3; dstNum++)
  1240.                     {
  1241.                         if (dstRectWrapped[dstNum] == false)
  1242.                             continue;
  1243.  
  1244.                         if ( (srcRect[srcNum].top < dstRect[dstNum].bottom) && 
  1245.                              (srcRect[srcNum].bottom > dstRect[dstNum].top) &&
  1246.                              (srcRect[srcNum].left < dstRect[dstNum].right) && 
  1247.                              (srcRect[srcNum].right > dstRect[dstNum].left) )
  1248.                         {
  1249.                             sectRect.left = SW_MAX(srcRect[srcNum].left, dstRect[dstNum].left);
  1250.                             sectRect.top = SW_MAX(srcRect[srcNum].top, dstRect[dstNum].top);
  1251.                             sectRect.right = SW_MIN(srcRect[srcNum].right, dstRect[dstNum].right);
  1252.                             sectRect.bottom = SW_MIN(srcRect[srcNum].bottom, dstRect[dstNum].bottom);
  1253.  
  1254.                             (*srcSpriteP->spriteCollideProc)(srcSpriteP, dstSpriteP, §Rect);
  1255.                         }
  1256.                     }
  1257.                 }
  1258.             }
  1259.             
  1260.             dstSpriteP = nextDstSpriteP;
  1261.         }
  1262.         
  1263.         srcSpriteP = nextSrcSpriteP;
  1264.     }
  1265. }
  1266.  
  1267.  
  1268. ///--------------------------------------------------------------------------------------
  1269. //    SWChangeCircularTileImage - this function simply calls SWUpdateCircularTileOnScreen
  1270. ///--------------------------------------------------------------------------------------
  1271.  
  1272. SW_FUNC void SWChangeCircularTileImage(
  1273.     SpriteWorldPtr    spriteWorldP,
  1274.     short            tileID,
  1275.     short            newImage)
  1276. {
  1277.         // Set the current image
  1278.     spriteWorldP->curTileImage[tileID] = newImage;
  1279.     
  1280.         // Update the tile image on screen
  1281.     SWUpdateCircularTileOnScreen(spriteWorldP, tileID);
  1282. }
  1283.  
  1284.  
  1285. ///--------------------------------------------------------------------------------------
  1286. //    SWUpdateCircularTileOnScreen - this is actually quite similar to SWDrawCircularTile,
  1287. //    except that it calls SWUpdateTileOnScreen instead of SWDrawTile.
  1288. ///--------------------------------------------------------------------------------------
  1289.  
  1290. SW_FUNC void SWUpdateCircularTileOnScreen(
  1291.     SpriteWorldPtr    spriteWorldP,
  1292.     short            tileID)
  1293. {
  1294.     short        oldHorizScrollRectOffset, oldVertScrollRectOffset;
  1295.     Rect        oldVisScrollRect, rectA, rectB, rectC, rectD;
  1296.     Boolean        horizClip, vertClip;
  1297.  
  1298.     oldVisScrollRect = spriteWorldP->visScrollRect;
  1299.     oldHorizScrollRectOffset = spriteWorldP->horizScrollRectOffset;
  1300.     oldVertScrollRectOffset = spriteWorldP->vertScrollRectOffset;
  1301.     
  1302.     rectA = spriteWorldP->visScrollRect;
  1303.     
  1304.     
  1305.         // Wrap right side to the left
  1306.     if (rectA.right > spriteWorldP->scrollRectMoveBounds.right)
  1307.     {
  1308.         rectB.top = rectA.top;
  1309.         rectB.bottom = rectA.bottom;
  1310.         rectB.left = spriteWorldP->scrollRectMoveBounds.left;
  1311.         rectB.right = rectA.right - spriteWorldP->scrollRectMoveBounds.right;
  1312.         
  1313.         rectA.right = spriteWorldP->scrollRectMoveBounds.right;
  1314.         horizClip = true;
  1315.     }
  1316.     else
  1317.         horizClip = false;
  1318.     
  1319.     
  1320.         // Wrap bottom side to the top
  1321.     if (rectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
  1322.     {
  1323.         rectC.left = rectA.left;
  1324.         rectC.right = rectA.right;
  1325.         rectC.top = spriteWorldP->scrollRectMoveBounds.top;
  1326.         rectC.bottom = rectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
  1327.         
  1328.         rectA.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
  1329.         rectB.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
  1330.         vertClip = true;
  1331.     }
  1332.     else
  1333.         vertClip = false;
  1334.     
  1335.     
  1336.         // Update tiles in rectA
  1337.     spriteWorldP->visScrollRect = rectA;
  1338.     SWUpdateTileOnScreen(spriteWorldP, tileID);
  1339.         
  1340.     
  1341.         // Update tiles in rectB
  1342.     if (horizClip)
  1343.     {
  1344.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the tile at the left of the world
  1345.         
  1346.         spriteWorldP->visScrollRect = rectB;
  1347.         SWUpdateTileOnScreen(spriteWorldP, tileID);
  1348.         
  1349.         spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
  1350.     }
  1351.     
  1352.         // Update tiles in rectC
  1353.     if (vertClip)
  1354.     {
  1355.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the tile at the top of the world
  1356.  
  1357.         spriteWorldP->visScrollRect = rectC;
  1358.         SWUpdateTileOnScreen(spriteWorldP, tileID);
  1359.         
  1360.         spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
  1361.     }
  1362.     
  1363.         // Update tiles in rectD (corner piece)
  1364.     if (vertClip && horizClip)
  1365.     {
  1366.         rectD.left = rectB.left;
  1367.         rectD.right = rectB.right;
  1368.         rectD.top = rectC.top;
  1369.         rectD.bottom = rectC.bottom;
  1370.         
  1371.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the sprites at the left of the world
  1372.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the sprites at the top of the world
  1373.         
  1374.         spriteWorldP->visScrollRect = rectD;
  1375.         SWUpdateTileOnScreen(spriteWorldP, tileID);
  1376.         
  1377.         spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
  1378.         spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
  1379.     }
  1380.     
  1381.     
  1382.         // Restore visScrollRect now that we're done
  1383.     spriteWorldP->visScrollRect = oldVisScrollRect;
  1384. }
  1385.  
  1386.  
  1387. ///--------------------------------------------------------------------------------------
  1388. //    SWDrawTilesInCircularBackground
  1389. ///--------------------------------------------------------------------------------------
  1390.  
  1391. SW_FUNC OSErr SWDrawTilesInCircularBackground(
  1392.     SpriteWorldPtr    spriteWorldP)
  1393. {
  1394.     short        oldHorizScrollRectOffset, oldVertScrollRectOffset;
  1395.     Rect        oldVisScrollRect, rectA, rectB, rectC, rectD;
  1396.     Boolean        horizClip, vertClip;
  1397.     GWorldPtr    holdGWorld;
  1398.     GDHandle    holdGDH;
  1399.     
  1400.     GetGWorld( &holdGWorld, &holdGDH );
  1401.     
  1402.     if ( !spriteWorldP->tilingIsInitialized )
  1403.     {
  1404.         SWSetStickyIfError(kTilingNotInitialized);
  1405.         return kTilingNotInitialized;
  1406.     }
  1407.  
  1408.     
  1409.         // Save these values so we can restore them later
  1410.     oldVisScrollRect = spriteWorldP->visScrollRect;
  1411.     oldHorizScrollRectOffset = spriteWorldP->horizScrollRectOffset;
  1412.     oldVertScrollRectOffset = spriteWorldP->vertScrollRectOffset;
  1413.     
  1414.     rectA = spriteWorldP->visScrollRect;
  1415.     
  1416.     
  1417.         // Wrap right side to the left
  1418.     if (rectA.right > spriteWorldP->scrollRectMoveBounds.right)
  1419.     {
  1420.         rectB.top = rectA.top;
  1421.         rectB.bottom = rectA.bottom;
  1422.         rectB.left = spriteWorldP->scrollRectMoveBounds.left;
  1423.         rectB.right = rectA.right - spriteWorldP->scrollRectMoveBounds.right;
  1424.         
  1425.         rectA.right = spriteWorldP->scrollRectMoveBounds.right;
  1426.         horizClip = true;
  1427.     }
  1428.     else
  1429.         horizClip = false;
  1430.     
  1431.     
  1432.         // Wrap bottom side to the top
  1433.     if (rectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
  1434.     {
  1435.         rectC.left = rectA.left;
  1436.         rectC.right = rectA.right;
  1437.         rectC.top = spriteWorldP->scrollRectMoveBounds.top;
  1438.         rectC.bottom = rectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
  1439.         
  1440.         rectA.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
  1441.         rectB.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
  1442.         vertClip = true;
  1443.     }
  1444.     else
  1445.         vertClip = false;
  1446.     
  1447.     
  1448.         // Draw tiles in the main piece
  1449.     spriteWorldP->visScrollRect = rectA;
  1450.     (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectA, true);
  1451.     
  1452.     
  1453.         // Draw tile in rectB
  1454.     if (horizClip)
  1455.     {
  1456.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the tiles at the left of the world
  1457.         
  1458.         spriteWorldP->visScrollRect = rectB;
  1459.         (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectB, false);
  1460.         
  1461.         spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
  1462.     }
  1463.     
  1464.         // Draw tile in rectC
  1465.     if (vertClip)
  1466.     {
  1467.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the tiles at the top of the world
  1468.         
  1469.         spriteWorldP->visScrollRect = rectC;
  1470.         (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectC, false);
  1471.         
  1472.         spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
  1473.     }
  1474.     
  1475.         // Draw tile in rectD (corner piece)
  1476.     if (vertClip && horizClip)
  1477.     {
  1478.         rectD.left = rectB.left;
  1479.         rectD.right = rectB.right;
  1480.         rectD.top = rectC.top;
  1481.         rectD.bottom = rectC.bottom;
  1482.         
  1483.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the sprites at the left of the world
  1484.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the sprites at the top of the world
  1485.         
  1486.         spriteWorldP->visScrollRect = rectD;
  1487.         (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectD, false);
  1488.         
  1489.         spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
  1490.         spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
  1491.     }
  1492.     
  1493.         // Restore visScrollRect now that we're done
  1494.     spriteWorldP->visScrollRect = oldVisScrollRect;
  1495.     
  1496.     
  1497.         // Restore the original port
  1498.     SetGWorld( holdGWorld, holdGDH );
  1499.     
  1500.     return noErr;
  1501. }
  1502.  
  1503.  
  1504. ///--------------------------------------------------------------------------------------
  1505. //    SWDrawCircularTile
  1506. ///--------------------------------------------------------------------------------------
  1507.  
  1508. SW_FUNC void SWDrawCircularTile(
  1509.     SpriteWorldPtr    spriteWorldP,
  1510.     short            dstTileLayer,
  1511.     short            tileRow,
  1512.     short            tileCol,
  1513.     short            tileID)
  1514. {
  1515.     short        oldHorizScrollRectOffset, oldVertScrollRectOffset;
  1516.     Rect        tileRect, oldVisScrollRect, rectA, rectB, rectC, rectD;
  1517.     Boolean        horizClip, vertClip;
  1518.     
  1519.         // We must have a TileMap installed in the dstTileLayer to draw in it!
  1520.     if (spriteWorldP->tileLayerArray[dstTileLayer] == NULL)
  1521.         return;
  1522.     
  1523.     tileRect.top = tileRow * spriteWorldP->tileHeight;
  1524.     tileRect.left = tileCol * spriteWorldP->tileWidth;
  1525.     tileRect.bottom = tileRect.top + spriteWorldP->tileHeight;
  1526.     tileRect.right = tileRect.left + spriteWorldP->tileWidth;
  1527.  
  1528.         // Save these values so we can restore them later
  1529.     oldVisScrollRect = spriteWorldP->visScrollRect;
  1530.     oldHorizScrollRectOffset = spriteWorldP->horizScrollRectOffset;
  1531.     oldVertScrollRectOffset = spriteWorldP->vertScrollRectOffset;
  1532.     
  1533.     rectA = spriteWorldP->visScrollRect;
  1534.     
  1535.     
  1536.         // Wrap right side to the left
  1537.     if (rectA.right > spriteWorldP->scrollRectMoveBounds.right)
  1538.     {
  1539.         rectB.top = rectA.top;
  1540.         rectB.bottom = rectA.bottom;
  1541.         rectB.left = spriteWorldP->scrollRectMoveBounds.left;
  1542.         rectB.right = rectA.right - spriteWorldP->scrollRectMoveBounds.right;
  1543.         
  1544.         rectA.right = spriteWorldP->scrollRectMoveBounds.right;
  1545.         horizClip = true;
  1546.     }
  1547.     else
  1548.         horizClip = false;
  1549.     
  1550.     
  1551.         // Wrap bottom side to the top
  1552.     if (rectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
  1553.     {
  1554.         rectC.left = rectA.left;
  1555.         rectC.right = rectA.right;
  1556.         rectC.top = spriteWorldP->scrollRectMoveBounds.top;
  1557.         rectC.bottom = rectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
  1558.         
  1559.         rectA.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
  1560.         rectB.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
  1561.         vertClip = true;
  1562.     }
  1563.     else
  1564.         vertClip = false;
  1565.     
  1566.     
  1567.         // Draw tile in rectA
  1568.     if ( SW_RECT_IS_IN_RECT(tileRect, rectA) )
  1569.     {
  1570.         spriteWorldP->visScrollRect = rectA;
  1571.         SWDrawTile(spriteWorldP, dstTileLayer, tileRow, tileCol, tileID);
  1572.     }
  1573.     
  1574.         // Draw tile in rectB
  1575.     if (horizClip)
  1576.     {
  1577.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the tile at the left of the world
  1578.         
  1579.         if ( SW_RECT_IS_IN_RECT(tileRect, rectB) )
  1580.         {
  1581.             spriteWorldP->visScrollRect = rectB;
  1582.             SWDrawTile(spriteWorldP, dstTileLayer, tileRow, tileCol, tileID);
  1583.         }
  1584.         
  1585.         spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
  1586.     }
  1587.     
  1588.         // Draw tile in rectC
  1589.     if (vertClip)
  1590.     {
  1591.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the tile at the top of the world
  1592.         
  1593.         if ( SW_RECT_IS_IN_RECT(tileRect, rectC) )
  1594.         {
  1595.             spriteWorldP->visScrollRect = rectC;
  1596.             SWDrawTile(spriteWorldP, dstTileLayer, tileRow, tileCol, tileID);
  1597.         }
  1598.         
  1599.         spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
  1600.     }
  1601.     
  1602.         // Draw tile in rectD (corner piece)
  1603.     if (vertClip && horizClip)
  1604.     {
  1605.         rectD.left = rectB.left;
  1606.         rectD.right = rectB.right;
  1607.         rectD.top = rectC.top;
  1608.         rectD.bottom = rectC.bottom;
  1609.         
  1610.         spriteWorldP->horizScrollRectOffset = 0;  // Draw the sprites at the left of the world
  1611.         spriteWorldP->vertScrollRectOffset = 0;  // Draw the sprites at the top of the world
  1612.         
  1613.         if ( SW_RECT_IS_IN_RECT(tileRect, rectD) )
  1614.         {
  1615.             spriteWorldP->visScrollRect = rectD;
  1616.             SWDrawTile(spriteWorldP, dstTileLayer, tileRow, tileCol, tileID);
  1617.         }
  1618.         
  1619.         spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
  1620.         spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
  1621.     }
  1622.     
  1623.         // Put the new tileID in the TileMap (done in case the tile isn't visible in
  1624.         // any part of the visScrollRect, in which case SWDrawTile would never be called.)
  1625.     spriteWorldP->tileLayerArray[dstTileLayer]->tileMap[tileRow][tileCol] = tileID;
  1626.     
  1627.         // Restore visScrollRect now that we're done
  1628.     spriteWorldP->visScrollRect = oldVisScrollRect;
  1629. }
  1630.  
  1631.